import ctypes
import json
import os
import re
import subprocess
import psutil
import winreg

import sys
from pathlib import Path
root_dir = Path(__file__).resolve().parents[2]  # 向上回溯两级到
sys.path.append(str(root_dir))
from voice_assistant.ai.ollama_client import simple_generate 
from voice_assistant.my_config import PROMPT_CMD, MODEL_URL, MODEL_NAME, PARAMS_PARSE

# 系统预定义路径
SYSTEM_PATHS = {
    # 系统工具
    "control_panel": "control",
    "device_manager": "devmgmt.msc",
    "task_manager": "taskmgr",
    "ip": ["ipconfig", "/all"],
    "registry_editor": "regedit",
    "command_prompt": "cmd.exe",
    "powershell": "powershell.exe",
    
    # 常用可执行文件
    "taskmgr.exe": "taskmgr.exe",
    "cmd.exe": "cmd.exe",
    "powershell.exe": "powershell.exe",
    "control.exe": "control.exe",
    "msconfig.exe": "msconfig.exe",
    "devmgmt.msc": "devmgmt.msc",
    
    # 新增应用路径映射
    "vscode": "Code.exe",
    "wechat": "WeChat.exe",
    "terminal": "wt.exe"  # Windows Terminal
}

def get_app_path_from_registry(app_name: str) -> str:
    """通过注册表查找应用程序路径"""
    # 规范化应用名称（添加 .exe 后缀）
    app_exe = app_name.lower() + ".exe" if not app_name.lower().endswith(".exe") else app_name.lower()
    
    # 可能存在的注册表路径
    registry_paths = [
        r"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths",
        r"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\App Paths"
    ]
    
    # 尝试不同的注册表根位置
    for root_key in [winreg.HKEY_LOCAL_MACHINE, winreg.HKEY_CURRENT_USER]:
        for sub_path in registry_paths:
            try:
                full_path = sub_path + "\\" + app_exe
                with winreg.OpenKey(root_key, full_path) as key:
                    path, _ = winreg.QueryValueEx(key, "")
                    # 扩展环境变量
                    expanded_path = os.path.expandvars(path)
                    if os.path.exists(expanded_path):
                        return expanded_path
            except FileNotFoundError:
                continue
            except Exception:
                continue
    
    # 尝试通过系统查找
    for path in os.environ["PATH"].split(os.pathsep):
        full_path = os.path.join(path, app_exe)
        if os.path.exists(full_path):
            return full_path
    
    return None

def set_volume(action: str, value: int):
    """使用Windows Core Audio API控制音量"""
    try:
        # 加载Windows多媒体库
        winmm = ctypes.WinDLL('winmm.dll')
        
        # 获取当前音量范围
        vol_range = ctypes.c_uint()
        winmm.waveOutGetVolume(0, ctypes.byref(vol_range))
        
        # 计算当前音量百分比
        current_vol = (vol_range.value & 0xFFFF) / 655.35
        
        # 根据指令计算新音量
        if action == "mute":
            # 直接静音
            winmm.waveOutSetVolume(0, 0)
            return "已静音"
        elif action == "up":
            new_vol = min(100, current_vol + value)
        elif action == "down":
            new_vol = max(0, current_vol - value)
        elif action == "set":
            new_vol = min(100, max(0, value))
        else:  # toggle操作
            if current_vol > 0:
                winmm.waveOutSetVolume(0, 0)
                return "已静音"
            else:
                # 恢复到50%音量
                winmm.waveOutSetVolume(0, 0x7FFF)
                return "音量已恢复"
        
        # 设置新音量 (0-65535)
        vol_level = int(new_vol * 655.35)
        winmm.waveOutSetVolume(0, vol_level)
        
        return f"音量设置为{int(new_vol)}%"
    
    except Exception as e:
        return f"音量控制失败: {str(e)}"

def execute_command(json_str: str) -> bool:
    """执行从 JSON 解析的命令"""
    try:
        if not json_str.startswith("{"):
            pattern = r'\{[\s\S]*?\}'
            match = re.search(pattern, json_str)
            if match:
                json_str = match.group(0)
            else:
                print("No valid JSON found in the input string.")
                return False
        data = json.loads(json_str)
        
        if not data.get("supported", True):
            print(f"Unsupported: {data.get('reason', 'Unknown reason')}")
            return False

        # 执行命令分发
        cmd_type = data["command"]
        target = data.get("target", "").lower().replace('"', '').replace("'", "")
        value = data.get("value", "")
        
        # 处理系统设置（音量和亮度）
        if cmd_type == "sys_volume":
            # 解析操作类型和数值
            action = "toggle"  # 默认操作
            vol_value = 10  # 默认10%
            
            # 确定操作类型
            if target in ["up", "down", "mute", "toggle"]:
                action = target
            elif "up" in target or "增大" in target or "调大" in target:
                action = "up"
            elif "down" in target or "减小" in target or "调小" in target:
                action = "down"
            elif "mute" in target or "静音" in target:
                action = "mute"
            
            # 解析音量值
            if value:
                try:
                    # 提取数值 (支持"10"或"10%"格式)
                    vol_value = int(re.search(r'\d+', value)[0])
                    vol_value = max(0, min(100, vol_value))
                except (TypeError, ValueError):
                    pass  # 保持默认值
                
            # 调用Windows API调节音量
            result = set_volume(action, vol_value)
            print(result)
            return True
                
        elif cmd_type == "sys_light":
            # 默认设置
            change = 10
            try:
                if value:
                    value = value.replace('%', '')
                    change = max(0, min(100, int(value)))
                else:
                    # 根据目标类型确定方向
                    if "down" in target or "调暗" in target or "降低" in target:
                        change = -10
                    elif "up" in target or "调亮" in target or "增加" in target:
                        change = 10
            except ValueError:
                pass
            
            # 使用PowerShell调节亮度
            ps_script = f"""
            $brightness = Get-WmiObject -Namespace root\\WMI -Class WmiMonitorBrightness | Select-Object -ExpandProperty CurrentBrightness
            $new_brightness = $brightness + {change}
            if ($new_brightness -gt 100) {{ $new_brightness = 100 }}
            if ($new_brightness -lt 0) {{ $new_brightness = 0 }}
            (Get-WmiObject -Namespace root\\WMI -Class WmiMonitorBrightnessMethods).WmiSetBrightness(1, $new_brightness)
            Write-Output "亮度已调整至$new_brightness%"
            """
            subprocess.Popen(["powershell", "-Command", ps_script], stdout=subprocess.PIPE)
            return True
        
        # 处理电源管理命令
        elif cmd_type == "sys_power":
            delay = 0  # 默认无延迟
            if value:
                try:
                    # 提取数字值，忽略单位
                    delay = int(''.join(filter(str.isdigit, str(value))))
                    # 如果单位是小时则转换为分钟
                    if "hour" in str(value).lower() or "小时" in str(value):
                        delay *= 60
                except ValueError:
                    pass
            
            if target == "lock":
                # 锁屏命令
                subprocess.run(["rundll32.exe", "user32.dll,LockWorkStation"])
                print("System locked")
                return True
                
            elif target == "sleep":
                # 睡眠命令
                subprocess.run(["rundll32.exe", "powrprof.dll,SetSuspendState", "0,1,0"])
                print("System entering sleep state")
                return True
                
            elif target == "hibernate":
                # 休眠命令
                subprocess.run(["shutdown", "/h"])
                print("System entering hibernate state")
                return True
                
            elif target == "shutdown":
                # 关机命令（支持延时）
                if delay > 0:
                    subprocess.run(["shutdown", "/s", "/t", str(delay * 60)])
                    print(f"System will shutdown in {delay} minutes")
                else:
                    subprocess.run(["shutdown", "/s", "/t", "0"])
                    print("System shutting down now")
                return True
                
            elif target == "restart":
                # 重启命令（支持延时）
                if delay > 0:
                    subprocess.run(["shutdown", "/r", "/t", str(delay * 60)])
                    print(f"System will restart in {delay} minutes")
                else:
                    subprocess.run(["shutdown", "/r", "/t", "0"])
                    print("System restarting now")
                return True

        elif cmd_type == "open_app":
            # 特殊系统应用处理
            if target == "calculator":
                subprocess.Popen("calc")
            elif target == "notepad":
                subprocess.Popen("notepad")
            else:
                # 从注册表或系统查找路径
                app_path = get_app_path_from_registry(target)
                if app_path:
                    subprocess.Popen(f'"{app_path}"')
                else:
                    print(f"Application '{target}' not found")
                    return False
        
        elif cmd_type == "close_app":
            # 规范化进程名
            proc_name = target
            if not proc_name.endswith(".exe"):
                proc_name += ".exe"
            
            # 查找并终止进程
            for proc in psutil.process_iter(['pid', 'name']):
                if proc.info['name'].lower() == proc_name:
                    try:
                        proc.kill()
                    except psutil.AccessDenied:
                        print(f"Permission denied to close {target}")
                        return False

        elif cmd_type == "open_file":
            file_path = os.path.abspath(target)
            if os.path.exists(file_path):
                # 使用指定应用或默认应用打开
                if "app" in data:
                    app_path = get_app_path_from_registry(data["app"])
                    if app_path:
                        subprocess.Popen([app_path, file_path])
                    else:
                        print(f"Specified app '{data['app']}' not found")
                        return False
                else:
                    os.startfile(file_path)
            else:
                print(f"File not found: {file_path}")
                return False
        
        elif cmd_type == "system_cmd":
            # 优先尝试预定义命令
            cmd = SYSTEM_PATHS.get(target)
            
            # 如果找不到预定义命令，尝试直接执行
            if not cmd:
                # 检查是否是可执行文件
                if target.endswith(('.exe', '.msc', '.cpl', '.bat', '.cmd')):
                    cmd = target
                # 检查是否是控制面板项
                elif target.startswith(('control ', 'control.exe ')):
                    cmd = target
                else:
                    print(f"Unsupported system command: {target}")
                    return False
            
            # 执行命令
            if isinstance(cmd, list):
                subprocess.run(cmd, shell=True)
            else:
                # 添加引号处理带空格路径
                if " " in cmd and not cmd.startswith('"'):
                    cmd = f'"{cmd}"'
                subprocess.Popen(cmd, shell=True)

    except json.JSONDecodeError:
        print("Invalid JSON format")
        return False
    except KeyError as e:
        print(f"Missing required field: {e}")
        return False
    except Exception as e:
        print(f"Execution error: {str(e)}")
        return False

    return True

#===========================================================
def ai_generate(cont):
    prompt = PROMPT_CMD.format(cont=cont)
    
    try:
        response = simple_generate(prompt, model=MODEL_NAME, base_url=MODEL_URL, **PARAMS_PARSE)
    except Exception as e:
        response = f"发生错误: {str(e)}"
    finally:
        return response

if __name__ == "__main__":
    while True:
        try:
            cont = input("请输入内容：")
            cmd = ai_generate(cont)
            print(cmd)
            execute_command(cmd)
        except KeyboardInterrupt:
            break
    # cmd = ai_generate("打开命令窗口")
    # print(cmd)
    # execute_command(cmd)